package com.msi;

import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.apache.log4j.Logger;

/**
 * Generator grafów zgodnych z treścą zadania
 * 
 * @author Michał Kołodziejski
 */
public class GraphGenerator {

    /**
     * Logger
     */
    private static Logger logger = Logger.getLogger(GraphGenerator.class);

    /**
     * Generuje graf zgodny z treścią zadania
     * 
     * @param n
     *            ilość węzłów grafu
     * @param r
     *            parametr
     * @return graf w postaci macierzy sąsiedztwa
     */
    public static Graph generateGraph(int n, double r) {
        // pusty graf
        Graph graph = Graph
                .createGraphByNeighbourMatrix(new ArrayList<List<Integer>>());

        List<Vertex> vertices = new ArrayList<Vertex>();

        Random rnd = new Random();
        Map<Integer, Point2D> coordMap = new HashMap<Integer, Point2D>();
        for (int i = 0; i < n; ++i) {
            Vertex v = new Vertex(i);
            /*
             * double x = (rnd.nextDouble() - 0.5) * 5; double y =
             * (rnd.nextDouble() - 0.5) * 5;
             */
            double x = rnd.nextDouble();
            double y = rnd.nextDouble();
            v.setX(x);
            v.setY(y);
            vertices.add(v);
            coordMap.put(i, new Point2D.Double(x * 200, y * 200));
        }
        graph.setCoordinates(coordMap);

        // wygenerowanie wszystkich liczb losowych ograniczenie ich przedziału
        int randomNumbersVectorLength = (n * (n - 1)) / 2;
        List<Double> randomNumbersVector = new ArrayList<Double>(
                randomNumbersVectorLength);
        double max = -1000000, min = 1000000;
        for (int i = 0; i < randomNumbersVectorLength; ++i) {
            double randomNumber = rnd.nextGaussian();
            // logger.debug(randomNumber);

            if (randomNumber < min) {
                min = randomNumber;
            } else if (randomNumber > max) {
                max = randomNumber;
            }
            randomNumbersVector.add(new Double(randomNumber));
        }
        // logger.debug("min = "+min);
        // logger.debug("max = "+max);
        // ograniczenie przedziału wygenerowanych liczb
        double width = (Math.abs(min) + Math.abs(max));
        double minAbs = Math.abs(min);
        for (int i = 0; i < randomNumbersVectorLength; ++i) {
            double number = randomNumbersVector.get(i).doubleValue();
            number += minAbs;
            number /= width;
            // logger.debug(number);
            randomNumbersVector.set(i, new Double(number));
        }

        // ustalenie sąsiedztwa między wierzchołkami grafu
        Iterator<Double> it = randomNumbersVector.iterator();
        for (int i = 0; i < n - 1; ++i) {
            for (int j = i + 1; j < n; ++j) {
                Vertex v1 = vertices.get(i);
                Vertex v2 = vertices.get(j);

                double x = it.next();
                double distance = Math.sqrt(Math.pow(v1.getX() - v2.getX(), 2)
                        + Math.pow(v1.getY() - v2.getY(), 2));
                double exp = Math.exp(-r * distance);
                logger.debug("x = " + x + ", exp = " + exp + ", distance = "
                        + distance);
                if (x < exp) {
                    logger.debug("dodana krawędź [v1: " + v1.getId() + ", v2: "
                            + v2.getId() + "]");
                    v1.addNeighbour(v2);
                }
            }
        }

        // dodanie wierzchołków do grafu
        Map<Integer, Vertex> map = new HashMap<Integer, Vertex>();
        for (int i = 0; i < n; ++i) {
            map.put(i, vertices.get(i));
        }
        graph.setVertices(map);

        return graph;
    }
}
